import xml.etree.ElementTree as ET
import os
import time
import shutil
import re
import json
import requests
import logging
import subprocess
import threading
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import queue
import sqlite3  # 添加SQLite库
from pathlib import Path  # 添加Path类用于路径处理
from get_kodi_info import get_kodi_credentials, kodi_jsonrpc
from parse_playlist import get_playlist_items
from download_posters import extract_and_save_posters
from generate_poster import generate_poster

os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("gen_poster")

# Kodi收藏文件路径配置
POSSIBLE_FAVOURITES_PATHS = [
    "/storage/.kodi/userdata/favourites.xml",  # 默认路径
    "/home/osmc/.kodi/userdata/favourites.xml",  # OSMC系统路径
    "/root/.kodi/userdata/favourites.xml",  # 根用户路径
    "/kodi/userdata/favourites.xml"  # 容器环境路径
]

# Kodi视频数据库路径配置
POSSIBLE_VIDEO_DB_PATHS = [
    "/storage/.kodi/userdata/Database/MyVideos131.db",  # 默认路径
    "/home/osmc/.kodi/userdata/Database/MyVideos131.db",  # OSMC系统路径
    "/root/.kodi/userdata/Database/MyVideos131.db",  # 根用户路径
    "/kodi/userdata/Database/MyVideos131.db"  # 容器环境路径
]

# 尝试找到实际存在的收藏文件路径
FAVOURITES_XML_PATH = None
for path in POSSIBLE_FAVOURITES_PATHS:
    if os.path.exists(path):
        FAVOURITES_XML_PATH = path
        logger.info(f"找到Kodi收藏文件: {FAVOURITES_XML_PATH}")
        break

if not FAVOURITES_XML_PATH:
    logger.warning("未找到Kodi收藏文件，将使用默认路径")
    FAVOURITES_XML_PATH = POSSIBLE_FAVOURITES_PATHS[0]

# 尝试找到实际存在的视频数据库路径
VIDEO_DB_PATH = None
for path in POSSIBLE_VIDEO_DB_PATHS:
    if os.path.exists(path):
        VIDEO_DB_PATH = path
        logger.info(f"找到Kodi视频数据库: {VIDEO_DB_PATH}")
        break

if not VIDEO_DB_PATH:
    logger.warning("未找到Kodi视频数据库，将使用默认路径")
    VIDEO_DB_PATH = POSSIBLE_VIDEO_DB_PATHS[0]

DATA_FOLDER = "data"
TEMP_FOLDER = "temp"
OUTPUT_FOLDER = "output"  # 封面统一保存路径

os.makedirs(DATA_FOLDER, exist_ok=True)
os.makedirs(TEMP_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)

# 全局变量
is_main_running = False
main_lock = threading.Lock()
change_event_queue = queue.Queue()
last_processed_mtime = 0

# 新增变量，用于记录脚本开始处理时的文件修改时间
initial_mtime = 0

class FavouritesHandler(FileSystemEventHandler):
    """监控favourites.xml文件变化的处理类"""
    def on_modified(self, event):
        if not event.is_directory and event.src_path.endswith('favourites.xml'):
            logger.info(f"检测到favourites.xml文件变更: {event.src_path}")
            change_event_queue.put(event)

def translate_text(text):
    """使用翻译接口翻译文本并提取实际翻译内容"""
    url = f"https://translate.appworlds.cn/?text={text}&from=zh-CN&to=en"
    try:
        response = requests.get(url)
        response.raise_for_status()

        # 解析JSON响应
        result = response.json()

        # 提取实际翻译内容
        if result.get("code") == 200 and "data" in result:
            translation = result["data"]
            # 去除特殊符号
            translation = re.sub(r'[^\w\s]', '', translation)
            return translation
        else:
            print(f"翻译接口返回异常: {result}")
            return text  # 翻译失败时返回原文

    except (requests.RequestException, ValueError) as e:
        print(f"翻译请求失败: {e}")
        return text  # 发生异常时返回原文


def get_media_count(playlist_items):
    """统计媒体类型的数量"""
    media_types = {
        "movies": 0,
        "tvshows": 0,
        "episodes": 0,
        "songs": 0
    }
    for item in playlist_items:
        if "showtitle" in item:
            media_types["episodes"] += 1
        elif "artist" in item:
            media_types["songs"] += 1
        elif "year" in item:
            media_types["movies"] += 1
        elif "title" in item:
            media_types["tvshows"] += 1
    return media_types

def update_favourites_xml(favourites_xml_path, name, thumb_path):
    """更新favourites.xml中对应name的thumb路径，使用绝对路径"""
    print(f"封面绝对路径: {thumb_path}")
    
    # 解析XML文件
    try:
        tree = ET.parse(favourites_xml_path)
        root = tree.getroot()
    except FileNotFoundError:
        print(f"错误: 文件 {favourites_xml_path} 不存在")
        return False
    except Exception as e:
        print(f"解析XML文件时出错: {e}")
        return False
    
    # 查找并更新对应的收藏项
    updated = False
    for favourite in root.findall('favourite'):
        if favourite.get('name') == name:
            print(f"更新 {name} 的封面路径为: {thumb_path}")
            favourite.set('thumb', thumb_path)
            updated = True
    
    if not updated:
        print(f"警告: 未找到名为 '{name}' 的收藏项")
    
    # 保存更新后的XML文件，指定编码为UTF-8
    try:
        # 创建备份文件
        backup_path = favourites_xml_path + ".bak"
        tree.write(backup_path, encoding='utf-8', xml_declaration=True)
        
        # 添加XML声明并写入新文件
        with open(favourites_xml_path, 'w', encoding='utf-8') as f:
            f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
            tree.write(f, encoding='unicode')
            
        print(f"已成功更新 {favourites_xml_path}")
        return True
    except Exception as e:
        print(f"保存XML文件时出错: {e}")
        return False


def restart_kodi():
    """使用systemctl restart kodi命令重启Kodi"""
    try:
        subprocess.run(["systemctl", "restart", "kodi"], check=True)
        print("Kodi重启命令已执行")
    except subprocess.CalledProcessError as e:
        print(f"重启Kodi失败: {e}")


def create_xsp_playlist(name, path):
    """
    创建Kodi智能播放列表(XSP)文件
    
    参数:
    name (str): 播放列表名称
    path (str): 媒体文件路径（DAV、SMB、NFS或本地路径）
    
    返回:
    str: 生成的XSP文件的绝对路径
    """
    # 创建临时文件夹（如果不存在）
    os.makedirs(TEMP_FOLDER, exist_ok=True)
    
    # 构建XSP文件路径
    xsp_filename = f"{name}.xsp"
    xsp_path = os.path.join(TEMP_FOLDER, xsp_filename)
    
    # 判断媒体类型，默认为movies
    media_type = "movies"
    if "音乐" in name or "歌曲" in name or path.endswith(('.mp3', '.flac', '.wav')):
        media_type = "music"
    elif "电视" in name or "剧集" in name or path.endswith(('.mkv', '.mp4', '.avi')):
        media_type = "tvshows"
    
    # 创建XSP文件内容 - 智能播放列表格式
    xsp_content = f"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<smartplaylist type="{media_type}">
    <name>{name}</name>
    <match>all</match>
    <rule field="path" operator="is">
        <value>{path}</value>
    </rule>
</smartplaylist>"""
    
    # 写入XSP文件
    try:
        with open(xsp_path, 'w', encoding='utf-8') as f:
            f.write(xsp_content)
        logger.info(f"成功创建智能播放列表: {xsp_path}")
        return os.path.abspath(xsp_path)
    except Exception as e:
        logger.error(f"创建智能播放列表失败: {e}")
        return None


def get_videodb_name(category, id):
    """
    通过SQLite直接查询Kodi数据库获取videodb分类的名称
    
    参数:
    category (str): 分类类型，如"sets", "genres"等
    id (int): 分类ID
    
    返回:
    str: 分类名称，如果获取失败则返回None
    """
    # 检查数据库文件是否存在
    if not os.path.exists(VIDEO_DB_PATH):
        logger.error(f"Kodi视频数据库不存在: {VIDEO_DB_PATH}")
        return None
    
    try:
        # 连接到SQLite数据库
        conn = sqlite3.connect(VIDEO_DB_PATH)
        cursor = conn.cursor()
        
        # 根据分类类型选择不同的查询
        if category == "sets":
            # 查询集合名称
            cursor.execute("SELECT strSet FROM sets WHERE idSet = ?", (id,))
            result = cursor.fetchone()
            if result:
                return result[0]
            else:
                logger.warning(f"未找到集合ID {id} 的记录")
                return None
                
        elif category == "genres":
            # 查询分类名称
            cursor.execute("SELECT name FROM genre WHERE genre_id = ?", (id,))
            result = cursor.fetchone()
            if result:
                return result[0]
            else:
                logger.warning(f"未找到分类ID {id} 的记录")
                return None
                
        else:
            logger.warning(f"不支持的分类类型: {category}")
            return None
            
    except sqlite3.Error as e:
        logger.error(f"SQLite查询错误: {e}")
        return None
    except Exception as e:
        logger.error(f"发生未知错误: {e}")
        return None
    finally:
        # 确保关闭数据库连接
        if conn:
            conn.close()


def create_videodb_xsp_playlist(name, path):
    """
    为videodb://类型的路径创建Kodi智能播放列表(XSP)文件
    
    参数:
    name (str): 播放列表名称
    path (str): videodb路径
    
    返回:
    str: 生成的XSP文件的绝对路径
    """
    # 创建临时文件夹（如果不存在）
    os.makedirs(TEMP_FOLDER, exist_ok=True)
    
    # 解析videodb路径
    # 示例: videodb://movies/sets/57/?setid=57
    # 或: videodb://movies/genres/13
    parts = path.split('/')
    
    # 确定媒体类型
    if "movies" in path:
        media_type = "movies"
    elif "tvshows" in path:
        media_type = "tvshows"
    else:
        logger.warning(f"未知的videodb媒体类型: {path}")
        return None
    
    # 确定分类类型和ID
    category = None
    id = None
    
    if "sets" in parts:
        category = "sets"
        try:
            id = int(parts[parts.index("sets") + 1])
        except (IndexError, ValueError):
            logger.error(f"无法从路径中提取集合ID: {path}")
            return None
        field = "set"
    elif "genres" in parts:
        category = "genres"
        try:
            id = int(parts[parts.index("genres") + 1])
        except (IndexError, ValueError):
            logger.error(f"无法从路径中提取分类ID: {path}")
            return None
        field = "genre"
    else:
        logger.warning(f"未知的videodb分类类型: {path}")
        return None
    
    # 获取分类名称
    category_name = get_videodb_name(category, id)
    if not category_name:
        logger.error(f"无法获取分类名称: {category} {id}")
        return None
    
    # 构建XSP文件路径
    xsp_filename = f"{name}.xsp"
    xsp_path = os.path.join(TEMP_FOLDER, xsp_filename)
    
    # 创建XSP文件内容
    xsp_content = f"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<smartplaylist type="{media_type}">
    <name>{name}</name>
    <match>all</match>
    <rule field="{field}" operator="contains">
        <value>{category_name}</value>
    </rule>
</smartplaylist>"""
    
    # 写入XSP文件
    try:
        with open(xsp_path, 'w', encoding='utf-8') as f:
            f.write(xsp_content)
        logger.info(f"成功创建videodb智能播放列表: {xsp_path}")
        return os.path.abspath(xsp_path)
    except Exception as e:
        logger.error(f"创建videodb智能播放列表失败: {e}")
        return None


def extract_playlist_path(favourite):
    """从favourite节点中提取播放列表路径，并根据路径类型进行相应处理"""
    # 从节点文本中提取路径
    cmd = favourite.text or ""
    name = favourite.get('name') or "未知收藏"
    
    # 尝试从命令文本中提取路径
    path = None
    
    # 查找包含playplaylist或ActivateWindow的命令
    if "playplaylist" in cmd.lower() or "activatewindow" in cmd.lower():
        # 尝试提取双引号中的路径
        start = cmd.find('"') + 1
        end = cmd.find('"', start)
        if start > 0 and end > start:
            path = cmd[start:end].strip()
    
    # 如果命令文本中没有，尝试从属性中获取
    if not path:
        for attr in ["file", "path", "filename"]:
            path = favourite.get(attr)
            if path:
                break
    
    # 如果没有找到路径，返回None
    if not path:
        logger.info(f"未从收藏项 '{name}' 中找到有效路径")
        return None
    
    # 首先检查是否是XSP文件
    if path.endswith('.xsp'):
        # 处理special路径为绝对路径
        if path.startswith("special://"):
            if "profile" in path:
                path = path.replace("special://profile/", "/storage/.kodi/userdata/")
            elif "home" in path:
                path = path.replace("special://home/", "/storage/.kodi/")
            elif "videoplaylists" in path:
                path = path.replace("special://videoplaylists/", "/storage/.kodi/userdata/playlists/video/")
            elif "musicplaylists" in path:
                path = path.replace("special://musicplaylists/", "/storage/.kodi/userdata/playlists/music/")
        
        logger.info(f"找到XSP播放列表: {path}")
        return path
    
    # 处理videodb://路径
    if path.startswith("videodb://"):
        logger.info(f"处理videodb路径: {path}")
        return create_videodb_xsp_playlist(name, path)
    
    # 对于非XSP路径，处理网络路径或本地媒体路径
    if path.startswith(('dav://', 'smb://', 'nfs://', '/storage')):
        logger.info(f"为收藏项 '{name}' 创建XSP智能播放列表，路径: {path}")
        return create_xsp_playlist(name, path)
    
    # 其他类型的路径，无法处理
    logger.warning(f"无法处理的路径类型: {path}")
    return None


def send_kodi_notification(credentials, title, message):
    """通过JSON-RPC向Kodi发送通知"""
    try:
        params = {
            "title": title,
            "message": message
        }
        kodi_jsonrpc('GUI.ShowNotification', params, credentials)
        print(f"✅ 已向Kodi发送通知: {title} - {message}")
    except Exception as e:
        print(f"⚠️ 发送Kodi通知失败: {e}")

def process_changes():
    """处理文件变更的主函数"""
    global last_processed_mtime, initial_mtime, favourite_count_before, favourite_count_after
    
    # 检查文件是否存在
    if not os.path.exists(FAVOURITES_XML_PATH):
        logger.warning(f"收藏文件 {FAVOURITES_XML_PATH} 不存在，跳过处理")
        return
    
    # 获取当前文件修改时间
    current_mtime = os.path.getmtime(FAVOURITES_XML_PATH)
    
    # 如果文件没有变化，不进行处理
    if current_mtime == last_processed_mtime:
        logger.info("文件未发生变化，跳过处理")
        return
    
    # 允许最多3次重试
    max_attempts = 3
    attempt = 1
    
    while attempt <= max_attempts:
        initial_mtime = os.path.getmtime(FAVOURITES_XML_PATH)
        logger.info(f"开始处理文件变更 (mtime: {initial_mtime}, 尝试次数: {attempt}/{max_attempts})")
        
        print("==== 开始自动生成封面 ====")
        credentials = get_kodi_credentials()
        print(f"✅ Kodi认证信息: {credentials}")
        
        try:
            tree = ET.parse(FAVOURITES_XML_PATH)
            root = tree.getroot()
            print(f"✅ 成功解析 {FAVOURITES_XML_PATH}")
        except FileNotFoundError:
            print(f"文件在解析过程中被删除: {FAVOURITES_XML_PATH}")
            return
        except Exception as e:
            print(f"❌ 解析favourites.xml失败: {e}")
            return
        
        # 记录更新前的收藏项数量
        favourite_count_before = len(root.findall('favourite'))
        print(f"发现 {favourite_count_before} 个收藏项")

        # 获取favourites.xml中所有收藏项的名称
        favourite_names = [favourite.get('name') for favourite in root.findall('favourite') if favourite.get('name')]

        # 清理data文件夹中favourites.xml里不存在的收藏夹对应的JSON文件
        for filename in os.listdir(DATA_FOLDER):
            if filename.endswith('.json'):
                name = os.path.splitext(filename)[0]
                if name not in favourite_names:
                    file_path = os.path.join(DATA_FOLDER, filename)
                    os.remove(file_path)
                    print(f"已删除不存在的JSON文件: {file_path}")
        
        processed_count = 0
        generated_count = 0
        updated_count = 0
        
        for index, favourite in enumerate(root.findall('favourite')):
            name = favourite.get('name')
            if not name:
                print(f"⚠️ 收藏项 #{index+1} 没有名称，跳过")
                continue
            
            playlist_path = extract_playlist_path(favourite)
            
            if not playlist_path:
                print("⚠️ 未找到播放列表路径，跳过")
                continue
            
            print(f"处理收藏项: {name}")
            
            # 转换为绝对路径（如果需要）
            if not playlist_path.startswith("/"):
                # 尝试几种可能的位置
                possible_locations = [
                    os.path.join("/storage/.kodi/userdata/playlists/video/", playlist_path),
                    os.path.join("/storage/playlists/video/", playlist_path),
                    playlist_path  # 假设已经是绝对路径
                ]
                
                for loc in possible_locations:
                    if os.path.exists(loc):
                        playlist_path = loc
                        break
            
            print(f"🔍 播放列表路径: {playlist_path}")
            
            # 检查文件是否存在
            if not os.path.exists(playlist_path):
                print(f"❌ 播放列表文件不存在: {playlist_path}")
                continue
            
            data_file_path = os.path.join(DATA_FOLDER, f"{name}.json")
            if os.path.exists(data_file_path):
                with open(data_file_path, 'r', encoding='utf-8') as f:
                    prev_data = json.load(f)
                print(f"✅ 找到历史数据: {data_file_path}")
            else:
                prev_data = {}
                print("ℹ️ 没有历史数据，将创建新数据")
            
            print("🔍 获取播放列表内容...")
            playlist_items = get_playlist_items(playlist_path, credentials)
            if not playlist_items:
                print("❌ 未找到媒体项，跳过")
                continue
            
            processed_count += 1
            media_count = get_media_count(playlist_items)
            print(f"📊 媒体统计: {media_count}")
            
            # 检查是否需要更新
            if media_count == prev_data.get('media_count', {}):
                print(f"✅ {name} 的媒体数量未改变，跳过更新")
                continue
            
            subtitle = translate_text(name)
            logger.info(f"翻译结果: 中文名称='{name}', 英文副标题='{subtitle}'")

            new_data = {
                "media_count": media_count,
                "subtitle": subtitle
            }

            with open(data_file_path, 'w', encoding='utf-8') as f:
                json.dump(new_data, f, ensure_ascii=False, indent=4)
            print(f"💾 已保存统计数据到: {data_file_path}")
            
            # 清理并准备临时文件夹
            shutil.rmtree(TEMP_FOLDER, ignore_errors=True)
            os.makedirs(TEMP_FOLDER)
            
            # 决定下载数量
            if sum(media_count.values()) >= 9:
                selected_items = playlist_items[:9]
            else:
                selected_items = playlist_items
            
            print(f"📥 准备下载 {len(selected_items)} 张海报")
            success_count = extract_and_save_posters(selected_items, TEMP_FOLDER)
            print(f"✅ 成功下载 {success_count} 张海报")
            
            if success_count > 0:
                poster_name = f"{name}.png"
                poster_path = os.path.join(OUTPUT_FOLDER, poster_name)  # 使用配置的输出路径
                print(f"🎨 生成封面: {poster_name}")
                
                # 生成海报
                result = generate_poster(title=name, subtitle=new_data["subtitle"], output_filename=poster_path)
                if result:
                    absolute_poster_path = os.path.abspath(poster_path)  # 获取绝对路径
                    print(f"✅ 封面已生成: {absolute_poster_path}")
                    generated_count += 1
                    
                    # 更新favourites.xml
                    update_result = update_favourites_xml(FAVOURITES_XML_PATH, name, absolute_poster_path)
                    if update_result:
                        updated_count += 1
        
        # 更新完成后再次检查收藏项数量
        try:
            tree = ET.parse(FAVOURITES_XML_PATH)
            root = tree.getroot()
            favourite_count_after = len(root.findall('favourite'))
            print(f"更新后收藏项数量: {favourite_count_after}")
            
            if favourite_count_after != favourite_count_before:
                print(f"⚠️ 检测到更新期间收藏项数量变化，从 {favourite_count_before} 变为 {favourite_count_after}")
                print(f"⚠️ 将尝试再次处理 ({attempt}/{max_attempts})")
                favourite_count_before = favourite_count_after  # 更新before值
                attempt += 1
                # 增加短暂延迟，给系统一些时间稳定
                time.sleep(1)
                continue  # 重新开始处理
            else:
                print("✅ 更新期间收藏项数量未变化，处理完成")
                break  # 处理完成，退出循环
        except Exception as e:
            print(f"❌ 检查更新后收藏项数量时出错: {e}")
            break
    
    # 更新最后处理时间
    last_processed_mtime = current_mtime
    
    # 输出处理结果
    print(f"==== 处理结果 ====")
    print(f"总收藏项: {favourite_count_before}")
    print(f"已处理: {processed_count}")
    print(f"已生成封面: {generated_count}")
    print(f"已更新XML: {updated_count}")
    
    # 发送Kodi通知
    if credentials:
        notification_title = "封面生成完成"
        notification_message = f"已处理 {processed_count} 个收藏项，生成 {generated_count} 个封面"
        send_kodi_notification(credentials, notification_title, notification_message)

def event_processor():
    """事件处理线程函数"""
    global is_main_running
    
    while True:
        # 获取队列中的事件
        event = change_event_queue.get()
        
        # 确保同一时间只有一个处理进程在运行
        with main_lock:
            if is_main_running:
                print("⚠️ 已有处理进程在运行，跳过此次事件")
                change_event_queue.task_done()
                continue
                
            is_main_running = True
            try:
                print("检测到文件变更，开始处理...")
                process_changes()
            finally:
                is_main_running = False
                change_event_queue.task_done()

# 添加收藏项计数器变量
favourite_count_before = 0
favourite_count_after = 0

# 主程序入口
if __name__ == "__main__":
    # 启动事件处理线程
    processor_thread = threading.Thread(target=event_processor, daemon=True)
    processor_thread.start()
    
    # 创建观察者并监控favourites.xml所在目录
    event_handler = FavouritesHandler()
    observer = Observer()
    observer.schedule(event_handler, path=os.path.dirname(FAVOURITES_XML_PATH), recursive=False)
    observer.start()
    
    # 首次启动时处理一次
    print("首次启动，开始处理收藏项...")
    with main_lock:
        is_main_running = True
        try:
            process_changes()
        finally:
            is_main_running = False
    
    print(f"开始监控 {FAVOURITES_XML_PATH} 文件变化...")
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    
    observer.join()
